package com.cherrypt.api.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cherrypt.api.common.enums.ResultEnum;
import com.cherrypt.api.common.exception.TipException;
import com.cherrypt.api.core.dao.CategoryDao;
import com.cherrypt.api.core.service.CategoryService;
import com.cherrypt.api.core.util.JackJsonUtils;
import com.cherrypt.api.model.dataobject.Category;
import com.cherrypt.api.model.dataobject.CategoryQuality;
import com.cherrypt.api.model.dto.CategoryDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;


/**
 * @author intent
 * @date 2019/8/3 14:24
 * @about <link href='http://zzyitj.xyz/'/>
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, Category> implements CategoryService {

    private static final Logger logger = LoggerFactory.getLogger(UserInfoServiceImpl.class);

    @Autowired
    private HashOperations<String, String, Object> hashOperations;

    @Value("${api.config.redis.category.value}")
    private String categoryValue;

    @Value("${api.config.redis.category.exp}")
    private long categoryExp;

    @Override
    public void saveRedisCategoryList(List<CategoryDto> categoryList) {
        for (CategoryDto categoryDtoList : categoryList) {
            hashOperations.put(categoryValue, String.valueOf(categoryDtoList.getId()), categoryDtoList);
        }
    }

    @Override
    public CategoryDto getRedisCategory(int cid) {
        return (CategoryDto) hashOperations.get(categoryValue, String.valueOf(cid));
    }

    @Override
    public List<CategoryDto> getRedisCategoryList() {
        List<CategoryDto> categoryDtoList = new ArrayList<>();
        List<Object> list = hashOperations.values(categoryValue);
        if (list != null && list.size() > 0) {
            for (Object o : list) {
                categoryDtoList.add((CategoryDto) o);
            }
        }
        categoryDtoList.sort(Comparator.comparingInt(CategoryDto::getId));
        return categoryDtoList;
    }

    @Override
    public List<CategoryDto> getCategoryList() throws TipException, IOException {
        List<CategoryDto> categoryDtoList = getRedisCategoryList();
        if (categoryDtoList == null || categoryDtoList.size() == 0) {
            List<Category> categoryList = this.list(new QueryWrapper<Category>().orderByAsc("id"));
            if (categoryList == null) {
                throw new TipException(ResultEnum.CATEGORY_ERROR);
            }
            // 把CategoryList转换为CategoryDtoList
            categoryDtoList = new ArrayList<>();
            for (Category category : categoryList) {
                categoryDtoList.add(getCategoryDto(category));
            }
            saveRedisCategoryList(categoryDtoList);
            logger.info("缓存categoryDtoList到Redis: {}", categoryList.size());
        }
        return categoryDtoList;
    }

    @Override
    public CategoryDto getCategory(int cid) throws TipException, IOException {
        CategoryDto categoryDto = getRedisCategory(cid);
        if (categoryDto == null) {
            Category category = getById(cid);
            if (category == null) {
                throw new TipException(ResultEnum.CATEGORY_ERROR);
            }
            categoryDto = getCategoryDto(category);
            // 既然其中一个分类都没有在缓存中了，那就说明CategoryList也没缓存
            // 缓存CategoryList
            getCategoryList();
        }
        return categoryDto;
    }

    private static CategoryDto getCategoryDto(Category category) throws IOException {
        CategoryDto categoryDto = new CategoryDto();
        categoryDto.setId(category.getId());
        categoryDto.setName(category.getName());
        categoryDto.setDescription(category.getDescription());
        CategoryQuality categoryQuality = JackJsonUtils.parseObject(category.getQuality(), CategoryQuality.class);
        categoryDto.setQuality(categoryQuality);
        return categoryDto;
    }
}
